<?php
/**
 * CK 开发框架
 * User: Clake
 * Date: 15/6/13
 * Time: 23:02
 */

namespace CK\Template;

use CK\Ex\ExNotFound;
use CK\Util\IO\File;
use CK\Util\Arr;

class Template {
    private $_conf = [
        'path'=>APP_TEMPLATE_PATH,
        'theme'=>'default',
        'cache_path'=> 'template/',
        'asset_path'=>'/assets/'
    ];

    private $_tpl_path;

    private $_tpl_cache_path;

    private $_tpl_theme;

    private $_var = [];

    private static $_instance;

    /**
     * @param null $conf
     *
     * @return self
     */
    public static function inst($conf=null) {
        if (!isset(self::$_instance)) {
            $class = get_called_class();
            self::$_instance = new $class($conf);
        }

        return self::$_instance;
    }

    public function __construct($conf) {
        if (is_array($conf)) {
            $this->_conf = array_merge($this->_conf,$conf);
        }
        $this->_conf['cache_path'] = APP_CACHE_PATH.$this->_conf['cache_path'];
        $this->_tpl_path = $this->_conf['path'];
        $this->_tpl_cache_path = $this->_conf['cache_path'];
        $this->_tpl_theme = !empty($this->_conf['theme'])?$this->_conf['theme'].'/':'';
    }

    /**
     * 解释模板内容
     * @param $content
     *
     * @return mixed
     */
    public function explain($content) {
//        $var_exp = "/\{(\\\$[0-9_a-zA-Z\[\]\'\"\$\.\x7f-\xff]+)\}/s";
        $var_exp = "/\\{\\\$([0-9_a-zA-Z\\[\\]\\'\"\$\\.\x7f-\xff]+)\\}/s";
        $if_exp = "/[\n\r\t]*\\{if\\s+(.+?)\\}[\n\r\t]*/is";
        $elseif_exp = "/[\n\r\t]*\\{elseif\\s+(.+?)\\}[\n\r\t]*/is";
        $else_exp = "/[\n\r\t]*\\{else\\}[\n\r\t]*/is";
        $endif_exp = "/[\n\r\t]*\\{\\/if\\}[\n\r\t]*/is";
        $loop_exp = "/[\n\r\t]*\\{loop\\s+(\\S+)\\s+(\\S+)\\}[\n\r\t]*/is";
        $loop2_exp = "/[\n\r\t]*\\{loop\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\}[\n\r\t]*/is";
        $loopend_exp = "/[\n\r\t]*\\{\\/loop\\}[\n\r\t]*/is";
        $lang_exp = "/\\{lang\\s+(.+?)\\}/is";
        $templet_exp = "/[\n\r\t]*\\{import\\s+(\\S+)\\}[\n\r\t]*/is";
        $templet2_exp = "/[\n\r\t]*\\{import\\s+(\\S+)\\s+(\\S+)\\}[\n\r\t]*/is";
        $echofunc_exp = "/[\n\r\t]*\\{echofunc\\s+(.+?)\\}[\n\r\t]*/is";
        $callfunc_exp = "/[\n\r\t]*\\{func\\s+(.+?)\\}[\n\r\t]*/is";
        $callfunc_rem = "/[\n\r\t]*\\{func\\s+(.+?)\\sreturn\\s(.+?)\\}[\n\r\t]*/is";
        $library_exp = "/[\n\r\t]*\\{library\\s+(.+?)\\}[\n\r\t]*/is";
        $code_exp = "/[\n\r\t]*\\{code\\}[\n\r\t]*/is";
        $codeend_exp = "/[\n\r\t]*\\{\\/code\\}[\n\r\t]*/is";
        $inner_code = "/[\n\r\t]*\\{code\\s(.+?)\\}[\n\r\t]*/is";
        $global_code = "/[\n\r\t]*\\{global\\s+(\\S+)\\}[\n\r\t]*/is";

        $content = preg_replace($var_exp,"<?php echo \$\\1?>",$content);
        $content = preg_replace("/\\<\\!\\-\\-\\s*\\{(.+?)\\}\\s*\\-\\-\\>/s", "{\\1}", $content);
//        $content = preg_replace_callback($lang_exp,function($matches){return language_var($matches[1]);},$content);
//        $content = preg_replace_callback($lang_exp,create_function('$matches','return language_var($matches[1]);'),$content);
        $content = preg_replace($if_exp,"<?php if (\\1) {?>",$content);
        $content = preg_replace($elseif_exp,"<?php } elseif (\\1) {?>",$content);
        $content = preg_replace($else_exp,"<?php } else {?>",$content);
        $content = preg_replace($endif_exp,"<?php }?>",$content);
        $content = preg_replace_callback($templet_exp,
            function($matches){
                $var_name = $matches[1];
                $var_name = substr($var_name, 0,1) === '$' ? $var_name : "'$var_name'";
                return "<?php \$this->display($var_name)?>";
            }
            ,$content);
        $content = preg_replace_callback($templet2_exp,
            function($matches){
                $var1 = $matches[1];
                $var2 = $matches[2];
                $var1 = substr($var1, 0,1) === '$' ? $var1 : "'$var1'";
                $var2 = substr($var2, 0,1) === '$' ? $var2 : "'$var2'";
                return "<?php \$this->display($var1,$var2)?>";
            }
            ,$content);
        $content = preg_replace($loop_exp,"\n<?php if(isset(\\1) && is_array(\\1)) { foreach (\\1 as \\2) {?>\n",$content);
        $content = preg_replace($loop2_exp,"\n<?php if(isset(\\1) && is_array(\\1)) { foreach (\\1 as \\2 => \\3) {?>\n",$content);
        $content = preg_replace($loopend_exp,"\n<?php } }?>\n",$content);
        $content = preg_replace($echofunc_exp,"<?php echo \\1;?>",$content);
        $content = preg_replace($callfunc_exp,"\n<?php \\1;?>",$content);
        $content = preg_replace($callfunc_rem,"\n<?php \\2=\\1;?>",$content);
        $content = preg_replace($library_exp,"\n<?php load_lib_file('\\1');?>",$content);
        $content = preg_replace($code_exp,"<?php ",$content);
        $content = preg_replace($codeend_exp," ?>",$content);
        $content = preg_replace($inner_code,"<?php \\1 ?>",$content);
        $content = preg_replace($global_code,"<?php \$GLOBALS['\\1'] = \$\\1; ?>",$content);
        return $content;
    }

    /**
     * 向PHP输出流显示模板内容
     * @param $tpl_name
     *
     * @throws ExNotFound
     */
    public function display($tpl_name) {
        $tpl_name = str_replace('.','/',trim($tpl_name));
        $tpl_file = $this->_tpl_path.$this->_tpl_theme.$tpl_name.'.html';
        $cache_file = $this->_tpl_cache_path.'tlp_'.str_replace('/','_',$this->_tpl_theme).
            str_replace('/','_',$tpl_name).'_'.substr(md5($tpl_file),0,16).'.php';

        if (File::Exists($tpl_file)) {
            if (!File::Exists($cache_file) || File::MTime($tpl_file) > File::MTime($cache_file)) {
                $content = $this->explain(File::Read($tpl_file));
                File::Write($cache_file,$content);
            }
            @extract($this->_var);
            include $cache_file;
        } else {
            throw new ExNotFound('Not found template "'.$tpl_name.'"');
        }
    }

    /**
     * 得到模板解释内容
     * @param $tpl_name
     *
     * @return string
     */
    public function fetch($tpl_name) {
        ob_start();
        $this->display($tpl_name);
        $content = ob_get_contents();
        ob_end_clean();
        ob_end_flush();
        return $content;
    }

    /**
     * 添加模板使用变量
     * @param $key
     * @param $value
     */
    public function assign($key,$value) {
        $this->_var[$key] = $value;
    }

    /**
     * 清除模板使用变量
     */
    public function clearAssign() {
        $this->_var = [];
    }

    public function vars($path) {
        return Arr::get($this->_var,$path,'.');
    }

    /**
     * 动态的修改主题
     * @param string $theme  主题名称
     *
     */
    public function theme($theme) {
        $this->_tpl_theme = $theme.'/';
    }
}